#include "Fl/Fl_Light_Button.H"
#include "Fl/Fl_Menu_Button.H"
#include "Fl/Fl_Round_Button.H"
#include "MeshListWidget.hpp"
#include "MeshView.hpp"
#include "ViewScene.hpp"
#include "MenuEvents.hpp"


MeshListWidget::MeshListWidget(int ax, int ay,int aw,int ah,const char * aLbl)
: Fl_Group(ax, ay, aw, ah, aLbl)
{
   mScroll = new Fl_Scroll(ax,ay,aw,ah);
   add(mScroll);
   resizable(mScroll);
   mScroll->resizable(mScroll);
}
void MeshListWidget::resize(int ax,int ay,int aw,int ah)
{
   Fl_Group::resize(ax,ay,aw,ah);
   for (size_t i = 0; i < mRows.size(); ++i)
   {
      Fl_Group* r = mRows[i]->mGroup;
      r->resize(r->x(), r->y(), aw, r->h());
   }
}
int MeshListWidget::GetSelected()
{
   for (size_t i = 0; i < mRows.size(); ++i)
   {
      if (mRows[i]->mSelector->value() != 0)
      {
         return i;
      }
   }
   return -1;
}

void MeshListWidget::UpdateRows()
{
   RowList newRows;
   bool added = false;
   for (size_t i = 0; i < ViewScene::GetInstance().mModels.size(); ++i)
   {
      MeshView* mesh = ViewScene::GetInstance().mModels[i];
      Row* r = FindRow(mesh);
      if (!r) { r = CreateRow(mesh); added = true; }
      newRows.push_back(r);
   }
   
   for (size_t i = 0; i < mRows.size(); i)
   {
      if (std::find(newRows.begin(), newRows.end(), mRows[i]) == newRows.end())
      {
         Row* r = mRows[i];
         mRows.erase(mRows.begin() + i);
         mScroll->remove(r->mGroup);
         //remove(r->mGroup);
         delete r;
      }
      else
      {
         ++i;
      }
   }
   mRows = newRows;

   int y = mScroll->y();
   for (size_t i = 0; i < mRows.size(); ++i)
   {
      Row* row = mRows[i];
      Fl_Group* grp = mRows[i]->mGroup;
      grp->position(grp->x(), y);
      y += grp->h();
      row->mLabel->copy_label(row->mMeshPtr->mName.c_str());
   }
   if (added) { mRows.back()->Select(); }
   mScroll->redraw();
}

namespace
{
   void cbRemove(Fl_Widget*, void* aDataPtr)
   {
      MeshListWidget::Row* row = (MeshListWidget::Row*)aDataPtr;
      MEvents("Remove Mesh", (MeshView*)row->mMeshPtr);
   }
   void cbProperties(Fl_Widget*, void* aDataPtr)
   {
      MeshListWidget::Row* row = (MeshListWidget::Row*)aDataPtr;
      MEvents("Mesh Properties", (MeshView*)row->mMeshPtr);
   }
   //void cbTetrahedralize(Fl_Widget*, void* aDataPtr)
   //{
   //   MEvents("Tetrahedralize");
   //}
   //void cbSimplify(Fl_Widget*, void* aDataPtr)
   //{
   //   MEvents("Simplify Surface");
   //}
   //void cbLoadLandmarks(Fl_Widget*, void* aDataPtr)
   //{
   //   ((MeshListWidget::Row*)aDataPtr)->Select();
   //   MEvents("Load Landmarks");
   //}
   //void cbRegister(Fl_Widget*, void* aDataPtr)
   //{
   //   ((MeshListWidget::Row*)aDataPtr)->Select();
   //   MEvents("Register To Landmarks");
   //}
   void cbSelect(Fl_Widget*, void* aDataPtr)
   {
      ((MeshListWidget::Row*)aDataPtr)->Select();
   }
   void cbShow(Fl_Widget*, void* aDataPtr)
   {
      MeshListWidget::Row* row = (MeshListWidget::Row*)aDataPtr;
      MeshView* meshPtr = (MeshView*)row->mMeshPtr;
      meshPtr->mVisible = row->mVisibility->value() != 0;
      MEvents("Redraw");
   }
   void cbRemoveLoops(Fl_Widget*, void* aDataPtr)
   {
      MeshListWidget::Row* row = (MeshListWidget::Row*)aDataPtr;
      MeshView* meshPtr = (MeshView*)row->mMeshPtr;
      //meshPtr->mVisible = row->mVisibility->value() != 0;
      MEvents("Redraw");
   }
}

Fl_Menu_Item MeshListWidget::mMenu[12] = {
   //{"Set Active", 0,  (Fl_Callback*)MeshPanel::cb_Set1, 0, 128, FL_NORMAL_LABEL, 0, 14, 0},
   {"Remove", 0,  (Fl_Callback*)cbRemove, 0, 0, FL_NORMAL_LABEL, 0, 14, 0},
   //{"Subdivide", 0,  (Fl_Callback*)MeshPanel::cb_Subdivide1, 0, 0, FL_NORMAL_LABEL, 0, 14, 0},
   {"Properties", 0,  (Fl_Callback*)cbProperties, 0, 0, FL_NORMAL_LABEL, 0, 14, 0},
//   {"Tetrahedralize", 0,  (Fl_Callback*)cbTetrahedralize, 0, 0, FL_NORMAL_LABEL, 0, 14, 0},
//   {"Simplify Surface", 0,  (Fl_Callback*)cbSimplify, 0, 0, FL_NORMAL_LABEL, 0, 14, 0},
//   {"Remove Loops", 0,  (Fl_Callback*)cbRemoveLoops, 0, 0, FL_NORMAL_LABEL, 0, 14, 0},
//   {"Load Landmarks", 0,  (Fl_Callback*)cbLoadLandmarks, 0, 0, FL_NORMAL_LABEL, 0, 14, 0},
//   {"Register", 0,  (Fl_Callback*)cbRegister, 0, 0, FL_NORMAL_LABEL, 0, 14, 0},
   {0,0,0,0,0,0,0,0,0}
};


MeshListWidget::Row::Row(MeshListWidget* aParent)
{
   mMeshListPtr = aParent;
   { Fl_Group* o = mGroup = new Fl_Group(0, 0, 170, 25);
   o->box(FL_UP_BOX);
   mVisibility = new Fl_Light_Button(150, 0, 15, 20);
   //mVisibility->when(FL_WHEN_CHANGED);
   mVisibility->user_data(this);
   mVisibility->callback(cbShow);
   { Fl_Menu_Button* o = new Fl_Menu_Button(120, 0, 29, 20);
   o->align(FL_ALIGN_LEFT|FL_ALIGN_INSIDE);
   o->copy(MeshListWidget::mMenu, this);
   //o->user_data(this);
   }
   { Fl_Box* o = mLabel = new Fl_Box(20, 3, 100, 17, "Mesh...");
   o->align(FL_ALIGN_LEFT|FL_ALIGN_INSIDE);
   //Fl_Group::current()->resizable(o);
   }
   { Fl_Round_Button* o = new Fl_Round_Button(0, 0, 100, 25);
   mSelector = o;
   o->down_box(FL_ROUND_DOWN_BOX);
   o->callback(cbSelect);
   o->user_data(this);
   }
   o->end();
   //Fl_Group::current()->resizable(o);
   }
   mGroup->resizable(mLabel);
   //mGroup->resizable(mGroup);
}
MeshListWidget::Row* MeshListWidget::FindRow(void* aMeshPtr)
{
   for (size_t i = 0; i < mRows.size(); ++i)
   {
      if (mRows[i]->mMeshPtr == aMeshPtr) return mRows[i];
   }
   return 0;
}
MeshListWidget::Row* MeshListWidget::CreateRow(MeshView* aMeshPtr)
{
   Row* r = new Row(this);
   r->mGroup->resize(r->mGroup->x(), r->mGroup->y(), mScroll->w(), r->mGroup->h());
   r->mMeshPtr = aMeshPtr;
   r->Update();
   mScroll->add(r->mGroup);
   return r;
}

void MeshListWidget::Row::Update()
{
   MeshView* mesh = (MeshView*)mMeshPtr;
   mLabel->copy_label(mesh->mName.c_str());
   mVisibility->value(mesh->mVisible ? 1 : 0);
}

void MeshListWidget::Row::Select()
{
   //mSelector->value(1); 
   mMeshListPtr->SelectRow(this);
   ViewScene::GetInstance().SetSelectedMesh(mMeshPtr);
}

void MeshListWidget::SelectRow(Row* aRow)
{
   for (size_t i = 0; i < mRows.size(); ++i)
   {
      if (aRow != mRows[i]) mRows[i]->mSelector->value(0);
      else mRows[i]->mSelector->value(1);
   }
}

void MeshListWidget::UpdateSelected()
{
   MeshView* meshPtr = ViewScene::GetInstance().GetSelectedMesh();
   for (size_t i = 0; i < mRows.size(); ++i)
   {
      if (mRows[i]->mMeshPtr == meshPtr)
      {
         SelectRow(mRows[i]);
      }
   }
}
